/********************************
 * Robinson Matrix Algorithm
 *
 * Copyright (C) 2009 CNRS
 * Author : Florent AVELLANEDA, Eugen CEPOI
 *
 *
 * All rights reserved.
 *
 *   This file is part of Robinson Matrix Algorithm.
 *
 *   Robinson Matrix Algorithm is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Robinson Matrix Algorithm is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Robinson Matrix Algorithm.  If not, see <http://www.gnu.org/licenses/>.
 *
 ***********************************************************************************/

#include <string>
#include <fstream>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <time.h>
#include <memory>


#include "../src/Matrix.h"
#include "../src/Algo.h"
#include "../src/PartialOrder.h"

#include "../src/AlgoGraph.h"
#include "../src/Util.h"
using namespace std;



void showHelp(std::string a)
{
    std::cerr << "usage: \t";
    std::cerr << "\t" << a;
    std::cerr << " [-i input-file]";
    std::cerr << " [-o output-file]";
    std::cerr << " [-r robinsons Matrix size for random generation]";
    std::cerr << " [-t delta]";
    std::cerr << " [-s]";
    std::cerr << std::endl;

    std::cerr << "\t-s : only switch order in matrix" << std::endl;
}

void showErrorSyntax(std::string a)
{
    std::cerr << "Syntax error" << std::endl;
    showHelp(a);
    exit(-1);
}

int main(int argc, char const* argv[])
{
    Matrix m;
    bool onlySwitch = false;
    bool testKnownMatrix = false;
    bool randRobinsonMatrix = false;
    bool fast=false;

    std::auto_ptr<std::ostream> OUT( NULL );

    int pos=1;

    while(pos < argc)
    {
        if( (strlen(argv[pos]) != 2) || (argv[pos][0] != '-') )
            showErrorSyntax(argv[0]);

        switch( argv[pos][1] )
        {
            case 'f' :
            case 'F' :
                ++pos;
                fast=true;
                break;

            case 'I' :
            case 'i' :
                {
                    if( m.getSize() > 0)
                        showErrorSyntax(argv[0]);

                    ifstream file( argv[pos+1] );
                    if( !file )
                    {
                        cerr << "can't open file : " << argv[1] << endl;
                        return -10;
                    }

                    file >> m;

                    pos+=2;

                    break;
                }

            case 'O' :
            case 'o' :
                if(OUT.get() != NULL)
                    showErrorSyntax(argv[0]);

                OUT.reset( new std::ofstream( argv[pos+1] ) ) ;

                pos+=2;
                break;

            case 'S' :
            case 's' :
                onlySwitch=true;
                ++pos;
                break;

            case 'R' :
            case 'r' :
            	double maxdelta;
            	maxdelta = atoi((argv[pos+2]));
            	m.randomGen3(atoi((argv[pos+1])), maxdelta);
            	randRobinsonMatrix = true;
            	pos+=3;
            	break;

            case 'T' :
            case 't' :
                testKnownMatrix = true;
                ++pos;
                break;

            case 'h' :
            case 'H' :
                showHelp(argv[0]);
                return 0;

            default :
                showErrorSyntax(argv[0]);
        }
    }

    if( m.getSize() == 0 )
        cin >> m;

    Matrix robinsonMatrix;
    double delta;

    /***************************************************************************************************************/
    /* To construct a matrix object based on your matrix call : Matrix m(vector<vector<unsigned int> yourMatrix); */
    /* fittingByRobinson is the function you have to call to solve the problem ( find the total order, and the robinsonian matrix )*/
    std::vector<unsigned int> totalOrder = Algo::fittingByRobinson(m, robinsonMatrix, delta, fast);
    /***************************************************************************************************************/
    if( totalOrder.size() != m.getSize() )
    {
        std::cerr << "Solution not complet (" << totalOrder.size() << " / " << m.getSize() << ")" << std::endl;
        return -3;
    }

    if( onlySwitch )
    {
        robinsonMatrix = m;

        for (unsigned int x = 0; x < totalOrder.size(); x++)
            for (unsigned int y = x+1; y < totalOrder.size(); y++)
                robinsonMatrix.set( x, y, m.get( totalOrder[x], totalOrder[y] ) );
    }

	if(OUT.get() != NULL)
    	*OUT << robinsonMatrix << std::endl;
    else
        cout << robinsonMatrix << endl;

    return 0;
}

